package cn.js.sangu.unitStore.utils;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.js.sangu.unitStore.entity.User;
import cn.js.sangu.unitStore.mapper.UserMapper;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;

/**
 * 说明：
 * 作者：linshuo
 * 日期：2024/8/11 10:32
 */
@Component
@Slf4j
public class TokenUtils {

    private static UserMapper USERMAPPER;

    public static final String TOKEN = "token";

    @Resource // jdk提供的按照名称装配，@autowired是按照类型注入
    private UserMapper userMapper;

    @PostConstruct // 创建Bean时执行
    public void setUserService() {
        USERMAPPER = userMapper;
    }

    /**
     * 生成Token
     * 
     * @param userId
     * @param sign
     * @return
     */
    public static String createToken(String userId, String sign) {
        return JWT.create().withAudience(userId) // 在创建JWT时通过用户信息来作为载荷,容量是数组，可以加多个用户信息
                .withExpiresAt(DateUtil.offsetHour(new Date(), 240)) // 当前时间向后偏移2小时作为过期时间
                .sign(Algorithm.HMAC256(sign)); // 以密码作为签名，作为token的密钥
    }

    /**
     * 获取当前用户对象
     * 从请求上下文获取用户信息，确保获取到的是当前请求的用户
     * 
     * @return 用户对象，如果无法获取则返回null
     */
    public static User getCurrentUser() {
        try {
            // 从请求上下文的持有者，获取RequestAttributes请求属性，强转为子类对象，以使用更多的方法
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
                    .getRequestAttributes();

            // 检查 attributes 是否为 null，避免潜在的空指针异常
            if (attributes == null) {
                log.warn("无法获取RequestAttributes，当前可能不在Web请求上下文中");
                return null;
            }

            HttpServletRequest request = attributes.getRequest();
            if (request == null) {
                log.warn("获取到的HttpServletRequest为null");
                return null;
            }

            String token = request.getHeader(TOKEN);
            if (StrUtil.isBlank(token)) {
                token = request.getParameter(TOKEN);
                if (StrUtil.isBlank(token)) {
                    log.debug("从请求头和请求参数获取token都为空，可能是登录或注册的初次请求");
                    return null;
                }
            }

            try {
                // 将token破译为用户信息
                String userIdStr = JWT.decode(token).getAudience().get(0);
                Integer userId = Integer.parseInt(userIdStr);

                User user = getUserById(userId);
                if (user == null) {
                    log.warn("根据token中的userId({})未找到用户", userId);
                }
                return user;
            } catch (Exception e) {
                log.error("解析token或查询用户信息失败: {}", e.getMessage());
                return null;
            }
        } catch (Exception e) {
            log.error("获取当前用户信息时发生异常: {}", e.getMessage());
            return null;
        }
    }

    /**
     * 根据用户ID获取用户对象
     * 
     * @param userId 用户ID
     * @return 用户对象，如果不存在则返回null
     */
    public static User getUserById(Integer userId) {
        if (userId == null) {
            return null;
        }
        try {
            User user = USERMAPPER.selectById(userId);
            if (user == null) {
                log.warn("根据用户ID({})未找到用户", userId);
            }
            return user;
        } catch (Exception e) {
            log.error("根据用户ID({})查询用户信息失败: {}", userId, e.getMessage());
            return null;
        }
    }
}
